#include <iostream>
#include <string>
#include <fermat/common/string.h>
#include <fermat/common/stop_watch.h>
#include <fermat/http/http_client.h>
#include <fermat/http/http_method.h>
#include <fermat/http/http_request_builder.h>
#include <fermat/http/http_buffered_message.h>

#include <fermat/http/http_header_builder_helper.h>
using  fermat::http::HttpClient;
using  fermat::Timestamp;
using  fermat::Stopwatch;
using  fermat::event::EventLoop;
using  fermat::event::EventLoopPtr;
using  fermat::net::TcpConnection;
using  fermat::net::TcpConnectionPtr;

int cnt;
Stopwatch w;
EventLoopPtr loop;
class TestRequestBuidler:public fermat::http::RequestBuilder {
public:
	TestRequestBuidler() {}
	void setBody(std::string b) {
		_body = b;
	}

	void setUp()
	{
		setUrl("/hello");
		_body.clear();
		setMethod(fermat::http::Method::get());
		setMinorVersion(1);
		
		fermat::http::HeaderBuilderHelper bh(this);
		bh.setContentLength(_body.size());
		bh.setContentType("text/plain");
		bh.setKeepAlive(true);
		bh.setHost("127.0.0.1");
	}

	void setBig()
	{
		setUrl("/big");
		setMethod(fermat::http::Method::get());
		setMinorVersion(1);
		//_body = "1111111111";
		_body.clear();
		fermat::http::HeaderBuilderHelper bh(this);
		
		bh.setContentLength(_body.size());
		bh.setContentType("text/plain");
		bh.setKeepAlive(true);
		bh.setHost("127.0.0.1");
	}
	virtual bool sendMessage( std::string & mes)
	{
		mes = requestLine();
		mes += headersToString();
		mes += "\r\n";
		mes += _body;
		return true;
	}
private:
	std::string _body;

};

namespace detail {
bool onResponse(fermat::http::ResponsePtr& res, fermat::http::HttpClient*hc) 
{
    /*
    BufferedResponse *br = (BufferedResponse *)res.get();
	std::cout<<br->status()<<"\n";
    std::cout<<"Content-Length: "<<br->header("Content-Length")<<std::endl;
    std::cout<<"body\r\n"<<br->body()<<"\n";
    */ 
    (void)res;
	cnt++;
	if(cnt >10000) {
        w.stop();
        std::cout<<"10000 request cost :"<< w.elapsed()<<"us"<<std::endl;   
		hc->shutdown();
		return true;
	}
    TestRequestBuidler *req = new TestRequestBuidler();
	fermat::http::RequestBuilderPtr s(req);
	req->setBig();
	hc->postRequest(s);
	return true;
}

bool onConnect(fermat::http::HttpClient* hc)
{
	cnt = 0;
	fermat::net::TcpConnectionPtr c =  hc->getConnection();
	c->setTcpLiner(true, 0);
	TestRequestBuidler *req = new TestRequestBuidler();
	fermat::http::RequestBuilderPtr s(req);
	req->setUp();
	hc->postRequest(s);
	return true;
}

bool onClose(HttpClient* hc)
{
	(void)hc;
	loop->quit();
	return true;
}

bool onRequestWrite(fermat::http::RequestBuilderPtr& req, std::string& ms)
{
	TestRequestBuidler *r = (TestRequestBuidler *)req.get();

	r->sendMessage(ms);
		//std::cout<<ms<<std::endl;
		return true;
}

fermat::http::ResponsePtr factory()
{
	fermat::http::BufferedResponse *res = new fermat::http::BufferedResponse();
	return fermat::http::ResponsePtr(res);
}
}
int main()
{
	fermat::event::EventLoopPtr l(new EventLoop());
	loop = l;
	fermat::net::SocketAddress s;
	s.set("127.0.0.1","18088");
	std::string serverName("test");
	fermat::http::HttpClient hc(l, s, serverName);
	hc.setCloseCB(std::bind(detail::onClose,std::placeholders::_1));
	hc.setRequestWrite(std::bind(detail::onRequestWrite, std::placeholders::_1, std::placeholders::_2));
	hc.setResponseReady(std::bind(detail::onResponse, std::placeholders::_1, std::placeholders::_2));
	hc.setResponseFactory(std::bind(detail::factory));
	hc.setConnectCB(std::bind(detail::onConnect,std::placeholders::_1));
	hc.connect();
    w.start();
	l->loop();
	return 0;
}